/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 attackable_obstacle.h

	$Header: /heroes4/attackable_obstacle.h $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "attackable_obstacle.h"

#include "battlefield.h"
#include "combat_reader.h"
#include "compound_object_model.h"
#include "external_string.h"
#include "format_string.h"
#include "obstacle_type.h"
#include "pixel_24.h"
#include "stationary_combat_object.h"

namespace
{
	typedef t_counted_ptr<t_attackable_obstacle> t_attackable_obstacle_ptr;
};

// -----------------------------------------------------------------------
// stationary combat object which can be attacked
// -----------------------------------------------------------------------
t_attackable_obstacle::t_attackable_obstacle( t_combat_object_model_cache const& cache, 
										      int								 hits )
				     : t_compound_object( cache )
{
	m_hit_points = hits;
	m_wounds = 0;
}

// -----------------------------------------------------------------------
// stationary combat object which can be attacked
// -----------------------------------------------------------------------
int t_attackable_obstacle::get_total_hits(bool include_guardian_angel, t_spell ignore_effect) const
{
	return m_hit_points - m_wounds;
}

// -----------------------------------------------------------------------
// stationary combat object which can be attacked
// -----------------------------------------------------------------------
bool t_attackable_obstacle::is_alive() const
{
	return m_hit_points > m_wounds;
}

// -----------------------------------------------------------------------
// stationary combat object which can be attacked
// -----------------------------------------------------------------------
t_abstract_combat_object const* t_attackable_obstacle::get_const_object() const
{
	return m_center_segment;
}

t_combat_object_list t_attackable_obstacle::get_objects() const
{
	t_combat_object_list	result;
	int						i;

	for (i = 0; i < m_segments.size(); ++i)
		result.push_back( m_segments[i] );
	return result;
}

float t_attackable_obstacle::get_defense_basic( bool ranged ) const
{
	return 1.0f;
}

float t_attackable_obstacle::get_defense_bonus( bool ranged ) const
{
	return 1.0f;
}

bool t_attackable_obstacle::read( t_combat_reader& reader )
{
	if (!t_compound_object::read( reader ))
		return false;

	std::streambuf& stream = reader.get_stream();

	m_center_segment = reader.read_stationary_object();
	m_wounds = get<t_uint16>( stream );
	m_hit_points = get<t_uint16>( stream );
	return true;
}

bool t_attackable_obstacle::write( t_combat_writer& writer ) const
{
	if (!t_compound_object::write( writer ))
		return false;

	std::streambuf& stream = writer.get_stream();

	writer.write( m_center_segment );
	put<t_uint16>( stream, m_wounds );
	put<t_uint16>( stream, m_hit_points );
	return true;
}

// -----------------------------------------------------------------------
// get center segment of a multi-segment object
// -----------------------------------------------------------------------
void t_attackable_obstacle::place( t_battlefield& battlefield, t_map_point_2d const& point )
{
	int				i;
	t_map_point_2d	footprint_size;
	int				segment_size;
	t_map_point_2d	center;
	t_map_point_2d  cell_point = point >> k_battlefield_subcell_shift;

	t_compound_object::place( battlefield, point );
	footprint_size = m_model->get_footprint_size();
	segment_size = m_segments[0]->get_footprint_size();

	if ((footprint_size.column / segment_size) & 1)
		center.column = cell_point.column + ((footprint_size.column - segment_size) >> 1);
	else
		center.column = cell_point.column + (footprint_size.column >> 1);
	if ((footprint_size.row / segment_size) & 1)
		center.row = cell_point.row + ((footprint_size.row - segment_size) >> 1);
	else
		center.row = cell_point.row + (footprint_size.row >> 1);
	
	for (i = 0; i < m_segments.size(); i++)
	{
		cell_point = m_segments[i]->get_cell_position();
		if (cell_point == center)
			break;
	}
	assert( i < m_segments.size() );
	m_center_segment = m_segments[i];
	battlefield.added( this );
}

// -----------------------------------------------------------------------
// fade all segments in
// -----------------------------------------------------------------------
void t_attackable_obstacle::fade_in( t_battlefield& battlefield, int alpha, t_combat_action_message const & message )
{
	int i;

	for (i = 0; i < m_segments.size(); i++)
		m_segments[i]->fade_in( battlefield, alpha, message );
}


void t_attackable_obstacle::remove( t_battlefield& battlefield )
{
	if (m_removed)
		return;

	battlefield.removed( this );
	t_compound_object::remove( battlefield );
}

// -----------------------------------------------------------------------
// apply any damage the creature may have received
// -----------------------------------------------------------------------
void t_attackable_obstacle::apply_damage( t_battlefield& battlefield, bool animate_death )
{
	int damage = get_new_damage();
	int i;

	if (damage == 0)
		return;

	std::string text = format_string( "-%i", m_new_damage );

	m_wounds += m_new_damage;
	m_new_damage = 0;
	battlefield.add_text( *m_center_segment, text, t_pixel_24(255,255,255) );
	if (m_wounds >= m_hit_points)
	{
		for (i = 0; i < m_segments.size(); i++)
			m_segments[i]->fade_out( battlefield, m_new_damage_message );
	}

	m_new_damage_message.clear();
}

static t_external_string const k_text_rock( "rock.combat" );

std::string t_attackable_obstacle::get_object_name() const
{
	return k_text_rock;
}
